/*

 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.springblade.upgrade.controller;

import cn.hutool.core.util.IdUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.api.R;
import org.springblade.modules.system.domain.BladeFile;
import org.springblade.upgrade.config.entity.PackageConfig;
import org.springblade.upgrade.config.service.IPackageBackendConfigService;
import org.springblade.upgrade.config.service.IPackageFrontConfigService;
import org.springblade.upgrade.constant.PackageUploadUtil;
import org.springblade.upgrade.log.entity.PackageLog;
import org.springblade.upgrade.log.service.IPackageLogService;
import org.springblade.upgrade.record.entity.UpgradeRecord;
import org.springblade.upgrade.record.service.IUpgradeRecordService;
import org.springblade.upgrade.upload.vo.FilePojoVo;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 升级包
 *
 * @author Chill
 */
@Slf4j
@RestController
@RequestMapping("/package/manage")
public class PackageManageController {

    @Resource
    private IPackageLogService packageLogService;

    @Resource
    private IPackageBackendConfigService packageBackendConfigService;

    @Resource
    private IPackageFrontConfigService packageFrontConfigService;
    @Resource
    private IUpgradeRecordService recordService;

    /**
     * 下载文件
     *
     * @param fileId:   文件id
     * @param response: 相应
     * @throws Exception：异常
     */
    @RequestMapping(path = "/download/{fileId}", method = RequestMethod.GET)
    public void download(@PathVariable String fileId, HttpServletResponse response) throws Exception {
        PackageLog fileInfo = this.packageLogService.getById(fileId);
        if (fileInfo == null) {
            PackageUploadUtil.buildResponse(response, "文件不存在");
            return;
        }
        if (fileInfo.getConfigId() == null) {
            PackageUploadUtil.buildResponse(response, "文件配置ID不存在");
            return;
        }
        String fileName = fileInfo.getName();
        try {
            File file = PackageUploadUtil.getFile(fileInfo);
            if (!file.exists()) {
                PackageUploadUtil.buildResponse(response, "文件不存在");
                return;
            }
            response.reset();
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1"));
            OutputStream fileOut = response.getOutputStream();
            fileOut.write(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
            fileOut.flush();
        } catch (Exception ex) {
            PackageUploadUtil.buildResponse(response, "导出异常，" + ex.getMessage());
        }
    }

    /**
     * 合并文件
     *
     * @param po
     * @return
     * @throws Exception
     */
    @PostMapping("/uploadMerge")
    public R<BladeFile> uploadMerge(@RequestBody FilePojoVo po) throws Exception {
        try {
            PackageConfig config = null;
            if ("backend".equals(po.getUploadType())) {
                config = packageBackendConfigService.getById(po.getModuleName());
            } else {
                config = packageFrontConfigService.getById(po.getModuleName());
            }
            if (config == null) {
                return R.fail("configId不能为空");
            }
            //动态路径
            String saveAddress = PackageUploadUtil.formatAddress(po.getBatchId());
            String dir = PackageUploadUtil.trim(config.getSysSaveDir() + File.separator + saveAddress);


            //分片
            List<File> fileList = new ArrayList<>();
            File tempFile = null;
            String shardFilePath;
            boolean has;
            for (int i = 0; i < po.getShardTotal(); i++) {
                // 读取第i个分片
                shardFilePath = dir + "/" + po.getKey() + "." + (i + 1);
                has = false;
                for (int z = 0; z < 5; z++) {
                    tempFile = new File(shardFilePath);
                    if (tempFile.exists() && tempFile.length() > 0) {
                        has = true;
                        break;
                    }
                    Thread.sleep(1000 * (z + 1));
                }
                if (!has) {
                    throw new Exception("缺少分片，" + (i + 1));
                }
                fileList.add(tempFile);
            }
            String mergeFilePath = dir + "/" + po.getFileName();
            File newFile = new File(mergeFilePath);
            newFile.getParentFile().mkdirs();
            FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
            FileInputStream fileInputStream = null;//分片文件
            byte[] byt = new byte[10 * 1024 * 1024];
            int len;
            try {
                for (File file : fileList) {
                    // 读取第i个分片 );
                    fileInputStream = new FileInputStream(file);
                    while ((len = fileInputStream.read(byt)) != -1) {
                        outputStream.write(byt, 0, len);//一直追加到合并的新文件中
                    }
                }
            } finally {
                try {
                    if (fileInputStream != null) {
                        fileInputStream.close();
                    }
                    outputStream.close();
                    System.gc();
                } catch (Exception e) {
                }
            }
            for (File file : fileList) {
                file.setExecutable(true);
                file.setWritable(true);
                file.delete();
            }
            log.info("文件 {} 合并完成", po.getFileName());

            //保存记录
            int last = po.getFileName().lastIndexOf(".");
            String ext = "";
            if (last > 0 || last < po.getFileName().length() - 1) {
                ext = po.getFileName().substring(last + 1);
            }
            Long attachID = IdUtil.getSnowflake(1, 2).nextId();
            PackageLog attach = new PackageLog();
            attach.setLink("/api/package/manage/download/" + attachID);
            attach.setDomainUrl(config.getSysSaveDir());
            attach.setIsDeleted(0);
            attach.setOriginalName(po.getFileName());
            attach.setName(po.getFileName());
            attach.setId(attachID);
            attach.setAttachSize(newFile.length());
            attach.setExtension(ext);
            attach.setUploadType(po.getUploadType());
            attach.setStatus(0);
            attach.setCreateTime(new Date());
            attach.setUpdateTime(attach.getCreateTime());
            attach.setSaveAddress(saveAddress + "/" + po.getFileName());
            attach.setConfigId(config.getId());
            attach.setModuleName(config.getModuleName());
            attach.setModuleName(config.getModuleName());
            packageLogService.save(attach);

            //记录日志
            UpgradeRecord record = new UpgradeRecord();
            record.setLogName(attach.getModuleName() + "上传后台包");
            record.setLogType("上传");
            record.setLogTxt(attach.getModuleName() + "上传后台包" + po.getFileName());
            record.setCreateTime(new Date());
            recordService.save(record);
            return R.data(PackageUploadUtil.convert(attach));
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("文件分片 {} 保存失败", ex.getMessage(), ex);
            return R.fail(ex.getMessage());
        }
    }

    /**
     * 大文件分片上传
     *
     * @param file
     * @param po
     * @return
     * @throws Exception
     */
    @PostMapping("/uploadShard")
    public R<String> uploadShard(@RequestParam(value = "file") MultipartFile file, FilePojoVo po) throws Exception {
        try {
            PackageConfig config;
            if ("backend".equals(po.getUploadType())) {
                config = packageBackendConfigService.getById(po.getModuleName());
            } else {
                config = packageFrontConfigService.getById(po.getModuleName());
            }
            if (config == null) {
                return R.fail("configId不能为空");
            }
            //动态路径
            String saveAddress = PackageUploadUtil.formatAddress(po.getBatchId());
            String dir = PackageUploadUtil.trim(config.getSysSaveDir() + File.separator + saveAddress);
            File dest = new File(dir + "/" + po.getKey() + "." + po.getShardIndex());
            dest.getParentFile().mkdirs();
            // 分片文件保存到文件目录
            file.transferTo(dest);
            log.info("文件分片 {} 保存完成", po.getShardIndex());
            return R.data("success");
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("文件分片 {} 保存失败", ex.getMessage(), ex);
            return R.fail(ex.getMessage());
        }
    }


    /**
     * 删除文件
     *
     * @return R
     */
    @SneakyThrows
    @PostMapping("/remove")
    public R<String> removeFile(@RequestParam String fileId) {
        PackageLog fileInfo = this.packageLogService.getById(fileId);
        if (fileInfo == null) {
            return R.fail("文件不存在");
        }
        packageLogService.removeById(Long.valueOf(fileId));

        //记录日志
        UpgradeRecord record = new UpgradeRecord();
        record.setLogName("删除包");
        record.setLogType("删除");
        record.setLogTxt("删除包" + fileId);
        record.setCreateTime(new Date());
        recordService.save(record);
        return R.success("操作成功");
    }


}
